#pragma region Include
#include <windows.h>
#include <string.h>
#include <gdiplus.h>
#include <tchar.h>
#include <stdio.h>
#include <string>

#include "desktop_image.h"
#pragma endregion Include

using namespace Gdiplus;
using namespace std;

CDesktopImage::CDesktopImage()
{
}

CDesktopImage::~CDesktopImage()
{
}

bool CDesktopImage::GetDesktopImagePNG(const char *path)
{
	FILE *fp = NULL;
	
	fp = fopen(path, "r");
	if(fp)
	{
		fclose(fp);
		DeleteFile(path);
	}

	GetDesktopBitmap(DEFAULT_TMP_FILE);

	WCHAR *w_def_tmp_file = new WCHAR[strlen(DEFAULT_TMP_FILE) + 1];
	WCHAR *w_path = new WCHAR[strlen(path) + 1];

	memset(w_def_tmp_file, 0, sizeof(WCHAR)*(strlen(DEFAULT_TMP_FILE) + 1));
	memset(w_path, 0, sizeof(WCHAR)*(strlen(path) + 1));

	mbstowcs(w_def_tmp_file, DEFAULT_TMP_FILE, strlen(DEFAULT_TMP_FILE) + 1);
	mbstowcs(w_path, path, strlen(path) + 1);

	BMPtoPNG(w_def_tmp_file, w_path);
	
	delete [] w_def_tmp_file;
	delete [] w_path;

	fp = fopen(DEFAULT_TMP_FILE, "r");
	if(fp)
	{
		fclose(fp);
		DeleteFile(DEFAULT_TMP_FILE);
	}

	return true;
}

bool CDesktopImage::GetDesktopImageRgnPNG(const char *path, const RECT &rect)
{
	FILE *fp = NULL;
	
	fp = fopen(path, "r");
	if(fp)
	{
		fclose(fp);
		DeleteFile(path);
	}

	GetDesktopBitmapRgn(DEFAULT_TMP_FILE, rect.left, rect.top, 
		rect.right, rect.bottom);

	WCHAR *w_def_tmp_file = new WCHAR[strlen(DEFAULT_TMP_FILE) + 1];
	WCHAR *w_path = new WCHAR[strlen(path) + 1];

	memset(w_def_tmp_file, 0, sizeof(WCHAR)*(strlen(DEFAULT_TMP_FILE) + 1));
	memset(w_path, 0, sizeof(WCHAR)*(strlen(path) + 1));

	mbstowcs(w_def_tmp_file, DEFAULT_TMP_FILE, strlen(DEFAULT_TMP_FILE) + 1);
	mbstowcs(w_path, path, strlen(path) + 1);
	
	
	fp = _wfopen(w_path, L"r");
	if(fp)
	{
		fclose(fp);
		DeleteFileW(w_path);
	}	

	BMPtoPNG(w_def_tmp_file, w_path);
	
	delete [] w_def_tmp_file;
	delete [] w_path;

	fp = fopen(DEFAULT_TMP_FILE, "r");
	if(fp)
	{
		fclose(fp);
		DeleteFile(DEFAULT_TMP_FILE);
	}

	return true;
}

RECT CDesktopImage::GetDesktopSize(RECT &rect)
{
	HDC hdcScreen = CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
	
	rect.left = rect.top = 0;
	rect.right = GetDeviceCaps(hdcScreen,HORZRES);
	rect.bottom = GetDeviceCaps(hdcScreen,VERTRES);

	DeleteDC(hdcScreen);

	return rect;
}

bool CDesktopImage::GetDesktopImageSeriesPNG(const char *path)
{
	RECT rect_desktop;
	string full_path(path), tmp_path;
	char num[5];
	memset(num, 0, 5);
	string::size_type index;

	full_path.append("desktop_%num%.png");

	this->GetDesktopSize(rect_desktop);

	int width = rect_desktop.right;
	int height = rect_desktop.bottom;

	int width_part = width / PARTS_X, width_add = width % PARTS_X;
	int height_part = height / PARTS_Y, height_add = height % PARTS_Y;

	for(int j = 0; j < PARTS_Y; j++)
	{
		for(int i = 0; i < PARTS_X; i++)
		{
			rect_desktop.left = i*width_part;
			
			rect_desktop.top = j*height_part;
			
			rect_desktop.right = width_part;
			if(i == (PARTS_X - 1)) 
				rect_desktop.right += width_add;

			rect_desktop.bottom = height_part; 
			if(j == (PARTS_Y - 1))
				rect_desktop.bottom += height_add;

			tmp_path.assign(full_path);
			index = tmp_path.find("%num%");
			sprintf(num, "%02d", i + j * PARTS_X);
			tmp_path.replace(index, 5, num, 2);
			
			GetDesktopImageRgnPNG(tmp_path.c_str(), rect_desktop);
		}
	}

	return true;
}

void CDesktopImage::GetDesktopBitmap(const char *path)
{
	HDC hdcScreen = CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
	HDC hdcMem = CreateCompatibleDC(hdcScreen);

	HBITMAP hbmMem = CreateCompatibleBitmap(hdcScreen,
							GetDeviceCaps(hdcScreen,HORZRES),
							GetDeviceCaps(hdcScreen,VERTRES));

	SelectObject(hdcMem,hbmMem);

	BitBlt(hdcMem,0,0,GetDeviceCaps(hdcScreen,HORZRES),
			GetDeviceCaps(hdcScreen,VERTRES),hdcScreen,0,0,SRCCOPY);

	SaveBM(path, hdcMem,hbmMem);

	DeleteDC(hdcScreen);
	DeleteObject(hbmMem);
	DeleteDC(hdcMem);
}

void CDesktopImage::GetDesktopBitmapRgn(const char *path, const int x, const int y, 
		const int width, const int height)
{
	HDC hdcScreen = CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
	
	//Sleep(100);
	
	HDC hdcMem = CreateCompatibleDC(hdcScreen);
	
	//Sleep(100);

	HBITMAP hbmMem = CreateCompatibleBitmap(hdcScreen,
							width,
							height);
							//GetDeviceCaps(hdcScreen,HORZRES),
							//GetDeviceCaps(hdcScreen,VERTRES));

	//Sleep(100);

	SelectObject(hdcMem,hbmMem);

	BitBlt(hdcMem, 0, 0, width, height, 
		hdcScreen, x, y, SRCCOPY);

	SaveBM(path, hdcMem,hbmMem);

	DeleteDC(hdcScreen);
	DeleteObject(hbmMem);
	DeleteDC(hdcMem);	
}
	
void CDesktopImage::SaveBM(const char *path, HDC hdcMem,HBITMAP hbmMem)
{	
	BITMAP bmMem;

	GetObject(hbmMem,sizeof(bmMem),&bmMem);

	BITMAPFILEHEADER bfh;
	BITMAPINFOHEADER bih;

	bih.biSize = sizeof(BITMAPINFOHEADER);
	bih.biWidth = bmMem.bmWidth;
	bih.biHeight = bmMem.bmHeight;
	bih.biPlanes = 1;
	bih.biBitCount = 32;
	bih.biCompression = BI_RGB;
	bih.biSizeImage = 0;
	bih.biXPelsPerMeter = 0;
	bih.biYPelsPerMeter = 0;
	bih.biClrUsed = 0;
	bih.biClrImportant = 0;

	DWORD dwLen = ((bmMem.bmWidth*bih.biBitCount+31)/32)*4*bmMem.bmHeight;

	HGLOBAL hGlMem = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT,dwLen);
	char *lpBitmap = (char*)GlobalLock(hGlMem);

	int nResult = GetDIBits(hdcMem,hbmMem,0,bmMem.bmHeight,lpBitmap,(LPBITMAPINFO)&bih,DIB_RGB_COLORS);
	
	if(!nResult)
		MessageBox(NULL,TEXT("Error GetDIBits"),TEXT("GetDIBits"),MB_OK);

	HANDLE hFile = CreateFile(path,
								GENERIC_WRITE,
								FILE_SHARE_WRITE,
								NULL,
								CREATE_ALWAYS,
								FILE_ATTRIBUTE_NORMAL,
								0);

	DWORD dwSizeOfDIB = dwLen + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	
	bfh.bfType = 0x4D42;
	bfh.bfSize = dwSizeOfDIB;
	bfh.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

	DWORD dwBytesWritten = 0, dwError = 0;

	WriteFile(hFile,(LPSTR)&bfh,sizeof(bfh),&dwBytesWritten,NULL);
	WriteFile(hFile,(LPSTR)&bih,sizeof(bih),&dwBytesWritten,NULL);
	BOOL bResult = WriteFile(hFile,(LPSTR)lpBitmap,dwLen,&dwBytesWritten,NULL);
	if(bResult == false)
	{
		MessageBox(NULL,TEXT("Error bitmap section"),TEXT("WriteFile"),MB_OK);
		dwError = GetLastError();
	}

	CloseHandle(hFile);

	GlobalUnlock(hGlMem);
	GlobalFree(hGlMem);
}

void CDesktopImage::BMPtoPNG(WCHAR *FileBMP,WCHAR *FilePNG)
{
	GdiplusStartupInput gsi;
	GdiplusStartupOutput gso;
	ULONG_PTR gdiplusToken;

	GdiplusStartup(&gdiplusToken,&gsi,&gso);

	UINT numEncoders;
	UINT size;

	GetImageEncodersSize(&numEncoders,&size);

	CLSID *encoderClsid;
	Status stat;
	Image *image = new Image(FileBMP);
	ImageCodecInfo *ici = (ImageCodecInfo*)malloc(size);

	GetImageEncoders(numEncoders,size,ici);

	for(UINT i=0;i < numEncoders;i++)
	{
		if(!wcscmp(ici[i].MimeType,L"image/png"))
		{
			encoderClsid = &ici[i].Clsid;
			break;
		}
	}

	stat = image->Save(FilePNG,encoderClsid,NULL);

	delete image;
	free(ici);
}